#ifndef STX_ALGORITHM_MOVE_ITERATOR_HPP_
#define STX_ALGORITHM_MOVE_ITERATOR_HPP_

#include <iterator>

namespace stx {

template <class Iterator>
class move_iterator
{
private:
    
    Iterator i;
    
public:
    
    typedef Iterator iterator_type;
    typedef typename std::iterator_traits<iterator_type>::iterator_category iterator_category;
    typedef typename std::iterator_traits<iterator_type>::value_type value_type;
    typedef typename std::iterator_traits<iterator_type>::difference_type difference_type;
    typedef typename std::iterator_traits<iterator_type>::pointer pointer;
#ifdef STX_HAS_RVALUE_REFERENCES
    typedef value_type&& reference;
#else
    typedef typename std::iterator_traits<iterator_type>::reference reference;
#endif

    move_iterator() : i()
    {
    }
    
    explicit move_iterator(Iterator x) : i(x)
    {
    }
    
    template <class U> move_iterator(const move_iterator<U>& u): i(u.base())
    {
    }
    
    Iterator base() const
    {
        return i;
    }
    
    reference operator*() const
    {
        return static_cast<reference>(*i);
    }
    
    pointer  operator->() const
    {
        typename std::iterator_traits<iterator_type>::reference ref = *i;
        return &ref;
    }
    
    move_iterator& operator++()
    {
        ++i;
        return *this;
    }
    
    move_iterator  operator++(int)
    {
        move_iterator tmp(*this);
        ++i;
        return tmp;
    }
    
    move_iterator& operator--()
    {
        --i;
        return *this;
    }
    
    move_iterator operator--(int)
    {
        move_iterator tmp(*this);
        --i;
        return tmp;
    }
    
    move_iterator operator+ (difference_type n) const
    {
        return move_iterator(i + n);
    }
    
    move_iterator& operator+=(difference_type n)
    {
        i += n;
        return *this;
    }
    
    move_iterator operator- (difference_type n) const
    {
        return move_iterator(i - n);
    }
    
    move_iterator& operator-=(difference_type n)
    {
        i -= n;
        return *this;
    }
    
    reference operator[](difference_type n) const
    {
        return static_cast<reference>(i[n]);
    }
};

template <class Iterator1, class Iterator2>
inline bool
operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() == y.base();
}

template <class Iterator1, class Iterator2>
inline bool
operator<(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() < y.base();
}

template <class Iterator1, class Iterator2>
inline bool
operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() != y.base();
}

template <class Iterator1, class Iterator2>
inline bool
operator>(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() > y.base();
}

template <class Iterator1, class Iterator2>
inline bool
operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() >= y.base();
}

template <class Iterator1, class Iterator2>
inline bool
operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() <= y.base();
}

template <class Iterator1, class Iterator2>
inline typename move_iterator<Iterator1>::difference_type
operator-(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y)
{
    return x.base() - y.base();
}

template <class Iterator>
inline move_iterator<Iterator>
operator+(typename move_iterator<Iterator>::difference_type n, const move_iterator<Iterator>& x)
{
    return move_iterator<Iterator>(x.base() + n);
}

template <class Iterator>
inline move_iterator<Iterator>
make_move_iterator(const Iterator& i)
{
    return move_iterator<Iterator>(i);
}

} // namespace stx

#endif // STX_ALGORITHM_MOVE_ITERATOR_HPP_
